#include <QPixmap>
#include <QtCore>
#include <QGraphicsRectItem>

#include "board.h"
#include "constants.h"
#include "boarditem.h"
#include "boardfigure.h"

#include "figurefactory.h"

Board::Board( QObject* parent ) : QGraphicsScene( parent )
{
  selected = 0;
  selectedFrameItem = 0;
  brush = QBrush( Qt::yellow );
  pen = QPen( brush, 0 );

  possibleMoveBrush = QBrush( Qt::red );
  possibleMovePen = QPen( possibleMoveBrush, 0 );

  for ( int i=0; i < Constants::BOARD_SIZE; i++ ) {
    for ( int j=0; j < Constants::BOARD_SIZE; j++ ) {
      board[i][j] = 0;
    }
  }
  createBoard();
}

void Board::createBoard()
{
  createFields();
  createFigures();
}

void Board::addItem( BoardItem* item )
{
  qDebug() << "Adding item: ";
  if ( item->isMovable() ) {
    int x = item->getBoardX();
    int y = item->getBoardY();
    BoardFigure* figure = (BoardFigure*) item;
    board[x][y] = figure;
  }
  QGraphicsScene::addItem( item );
}

void Board::mousePressEvent( QGraphicsSceneMouseEvent* event )
{
  QPointF pos = event->scenePos();

  QList<QGraphicsItem *> list = items( pos );
  if ( !list.size() ) return;

  QGraphicsItem* itemAddr = 0;
  for ( int i = 0; i < list.size(); i++ ) {
    if (    list.at( i )->zValue() == Constants::FIGURE_Z_LEVEL
         || list.at( i )->zValue() == Constants::FIELD_Z_LEVEL
       ) {
      itemAddr = list.at( i );
      break;
    }
  }

  qDebug() << "Item ADDR:" << itemAddr;
  if ( !itemAddr ) return;

  //
  // Now we have only BoardItem* items on scene
  //
  BoardItem* item = (BoardItem*) itemAddr;

  qDebug() << "Mouse pressed SCENE_X:" << pos.x() << " SCENE_Y:" << pos.y();

  Move* possibleMove = 0;
  if ( selected && item != selected ) {
    possibleMove = canMoveFigure( item->getBoardX(), item->getBoardY() );
    qDebug() << "Item:" << " X:" << item->getBoardX() << " Y:" << item->getBoardY();
    qDebug() << "Possible move:" << possibleMove;
    item->dumpObjectInfo();
  }

  if ( possibleMove ) {
    // Moving figure to new position
    qDebug() << "Moving figure to:" << possibleMove;
    makeMove( possibleMove );
  }
  else if ( selected && item->isMovable() ) {
    // Change selection
    qDebug() << "Selecting figure";
    select( item );
  }
  else if ( selected ) {
    // clear selection
    qDebug() << "UNselecting figure";
    unSelect();
  }
  else if ( selected == 0 && item->isMovable() ) {
    // Change selection
    qDebug() << "Selecting new figure";
    select( item );
  }
}

Move* Board::canMoveFigure( int x, int y )
{
  BoardFigure* figure = (BoardFigure*) selected;
  QList<Move*> moves = figure->getPossibleMoves( board );
  Move* result = 0;

  if ( moves.size() ) {
    for ( int i = 0; i < moves.size(); i++ ) {
      if ( moves.at(i)->getNewX() == x && moves.at(i)->getNewY() == y ) {
        result = moves.at(i);
        break;
      }
    }
  }
  qDebug() << "Returns possible move:" << result;
  return result;
}

void Board::makeMove( Move* move )
{
  qDebug() << "Making move: " << move->getNewX() << ", " << move->getNewY() << " MOVE:" << move;

  int oldX = move->getOldX();
  int oldY = move->getOldY();
  int newX = move->getNewX();
  int newY = move->getNewY();
  
  BoardFigure* item = board[oldX][oldY];

  Move* extraMove = move->getExtraMove();
  bool needExtraMove = false;
  int extraOldX, extraOldY, extraNewX, extraNewY;
  if ( extraMove != 0 ) {
    qDebug() << "Making EXTRA move: " << extraMove->getNewX() << ", " << extraMove->getNewY();
    extraOldX = extraMove->getOldX();
    extraOldY = extraMove->getOldY();
    extraNewX = extraMove->getNewX();
    extraNewY = extraMove->getNewY();
    needExtraMove = true;
  }

  item->move( newX, newY, board );
  if ( needExtraMove ) {
    BoardFigure* extraItem = board[extraOldX][extraOldY];
    extraItem->move( extraNewX, extraNewY, board );
  }

  unSelect();
}

void Board::createFields()
{
  for ( int i = 0; i < int( Constants::BOARD_SIZE ); i++ ) {
    for ( int j = 0; j < int( Constants::BOARD_SIZE ); j++ ) {
      BoardItem* item;
      if ( (i + j) % 2 == 0 ) {
        item = new BoardItem( i, j, QString(":/pics/black.svg") );
      }
      else {
        item = new BoardItem( i, j, QString(":/pics/white.svg") );
      }
      addItem( item );
    }
  }
}

void Board::createFigures()
{
  BoardFigure* item;
  int size = Constants::BOARD_SIZE;
  //
  // Placing pawns
  //
  FigureFactory* ff = new FigureFactory();

  for ( int i = 0; i < int( Constants::BOARD_SIZE ); i++ ) {
    item = ff->createFigure( i, size-7, QString("pawn"), Constants::COLOR_WHITE );
    addItem(item);
    item = ff->createFigure( i, size-2, QString("pawn"), Constants::COLOR_BLACK );
    addItem(item);
  }

  item = ff->createFigure( size-8, 0,      QString("rook"), Constants::COLOR_WHITE );
  addItem(item);
  item = ff->createFigure( size-1, 0,      QString("rook"), Constants::COLOR_WHITE );
  addItem(item);
  item = ff->createFigure( size-8, size-1, QString("rook"), Constants::COLOR_BLACK );
  addItem(item);
  item = ff->createFigure( size-1, size-1, QString("rook"), Constants::COLOR_BLACK );
  addItem(item);

  item = ff->createFigure( size-7, 0,      QString("knight"), Constants::COLOR_WHITE );
  addItem(item);
  item = ff->createFigure( size-2, 0,      QString("knight"), Constants::COLOR_WHITE );
  addItem(item);
  item = ff->createFigure( size-7, size-1, QString("knight"), Constants::COLOR_BLACK );
  addItem(item);
  item = ff->createFigure( size-2, size-1, QString("knight"), Constants::COLOR_BLACK );
  addItem(item);

  item = ff->createFigure( size-6, 0,      QString("bishop"), Constants::COLOR_WHITE );
  addItem(item);
  item = ff->createFigure( size-3, 0,      QString("bishop"), Constants::COLOR_WHITE );
  addItem(item);
  item = ff->createFigure( size-6, size-1, QString("bishop"), Constants::COLOR_BLACK );
  addItem(item);
  item = ff->createFigure( size-3, size-1, QString("bishop"), Constants::COLOR_BLACK );
  addItem(item);

  item = ff->createFigure( size-5, 0,      QString("queen"), Constants::COLOR_WHITE );
  addItem(item);
  item = ff->createFigure( size-4, 0,      QString("king"), Constants::COLOR_WHITE );
  addItem(item);
  item = ff->createFigure( size-5, size-1, QString("queen"), Constants::COLOR_BLACK );
  addItem(item);
  item = ff->createFigure( size-4, size-1, QString("king"), Constants::COLOR_BLACK );
  addItem(item);
}

void Board::select( BoardItem* boardItem )
{
  BoardFigure* item = (BoardFigure*) boardItem;

  QList<Move*> moves = item->getPossibleMoves( board );
  if ( moves.size() ) {
    for (int i = 0; i < moves.size(); ++i) {
      Move* move = moves.at(i);
      qDebug() << "Possible moves:[" << move->getNewX() << "][" << move->getNewY() << "]";
    }
  }

  if ( item == selected  ) {
    unSelect();
  }
  else {
    unSelect();
    selected = item;
    showPossibleMoves( moves );

    QRectF rect( 0, 0, Constants::FIELD_SIZE, Constants::FIELD_SIZE);
    selectedFrameItem = addRect(rect, pen, brush);
    selectedFrameItem->setPos( item->getScenePos() );
    selectedFrameItem->setZValue( Constants::FRAME_Z_LEVEL );
  }
}

void Board::unSelect()
{
  if ( selected ) {
    selected = 0;
    delete selectedFrameItem;
    hidePossibleMoves();
  }
}

void Board::showPossibleMoves( QList<Move*>& moves )
{
  for ( int i = 0; i < moves.size(); i++ ) {
    QRectF rect( 5, 5, Constants::FIELD_SIZE / 4, Constants::FIELD_SIZE / 4);
    QGraphicsItem* item = addRect(rect, possibleMovePen, possibleMoveBrush);
    item->setPos( BoardItem::calculateScenePos( moves.at(i)->getNewX(), moves.at(i)->getNewY() ) );
    item->setZValue( Constants::FRAME_Z_LEVEL );
    possibleMoveFrames.push_back( item );
  }
}

void Board::hidePossibleMoves()
{
  qDebug() << "Hiding possible moves";
  for ( int i = 0; i < possibleMoveFrames.size(); i++ ) {
    delete possibleMoveFrames.at(i);
  }
  possibleMoveFrames.clear();
}
